﻿(function ($) {

    // private variables
    var operators;

    $.fn.spAdvancedSearch = function (options) {

        operators = {
            general: {
                Eq: asResources.IsEqualTo,
                Neq: asResources.IsNotEqualTo,
                Gt: asResources.IsGreaterThan,
                Lt: asResources.IsLessThan,
                Geq: asResources.IsGreaterThanOrEqualTo,
                Leq: asResources.IsLessThanOrEqualTo,
                BeginsWith: asResources.BeginsWith,
                Contains: asResources.Contains
            },
            text: {
                Eq: asResources.IsEqualTo,
                Neq: asResources.IsNotEqualTo,
                BeginsWith: asResources.BeginsWith,
                Contains: asResources.Contains
            },
            number: {
                Eq: asResources.IsEqualTo,
                Neq: asResources.IsNotEqualTo,
                Gt: asResources.IsGreaterThan,
                Lt: asResources.IsLessThan,
                Geq: asResources.IsGreaterThanOrEqualTo,
                Leq: asResources.IsLessThanOrEqualTo
            },
            dateTime: {
                Eq: asResources.IsSameTimeTo,
                Neq: asResources.IsNotSameTimeTo,
                Gt: asResources.IsLaterThan,
                Lt: asResources.IsEarlierThan,
                Geq: asResources.IsLaterThanOrEqualTo,
                Leq: asResources.IsEarlierThanOrEqualTo
            },
            boolean: {
                True: asResources.IsYes,
                False: asResources.IsNo
            },
            user: {
                Eq: asResources.ContainsUser,
                Neq: asResources.NotContainsUser
            }
        };

        var con = { element: this };

        con.urlParams = getUrlParams();
        if (!con.urlParams.list) return this;

        // AND/OR
        this.append('<div class="cb-ui-row"><select name="andor" class="as-andor"><option value="And">' + asResources.AndCase + '</option><option value="Or">' + asResources.OrCase + '</option></select></div>');

        // filters
        con.filtersElement = $('<div class="as-filters"></div>').appendTo(this);

        // add filter anchor
        this.append('<div class="cb-ui-row"><a href="javascript:" class="as-add-filter">' + asResources.AddFilter + '</a></div>');

        // row limit
        this.append('<div class="cb-ui-row"><label class="as-label">' + asResources.NumberOfItemsToDisplay + '</label><input type="text" class="as-row-limit ms-input" style="width: 3em;" /></div>');

        // buttons
        this.append('<div class="cb-ui-row"><input type="button" value="' + asResources.OK + '" class="as-ok ms-ButtonHeightWidth" /> <input type="button" value="' + asResources.Cancel + '" class="as-cancel ms-ButtonHeightWidth" /> <input type="button" value="' + asResources.Reset + '" class="as-reset ms-ButtonHeightWidth" /></div>');

        // result area
        this.append('<div class="as-result"></div>');

        // client context
        con.context = SP.ClientContext.get_current();

        // detect region
        detectRegion();

        // list
        con.web = con.context.get_web();
        con.listId = new SP.Guid(con.urlParams.list);
        con.list = con.web.get_lists().getById(con.listId);
        con.fields = con.list.get_fields();
        con.defaultView = con.list.getView(SP.Guid.get_empty());
        con.defaultViewFields = con.defaultView.get_viewFields();
        con.filterCount = 0;
        con.orderByCount = 0;
        con.context.load(con.web);
        con.context.load(con.list);
        con.context.load(con.fields);
        con.context.load(con.defaultView);
        con.context.load(con.defaultViewFields);
        con.context.executeQueryAsync(function () {

            initFieldInfo(con);

            if (con.lookupListCount > 0) {
                con.lookupLists = {};
                var currentWebId = con.web.get_id().toString();
                var site = con.context.get_site();
                for (var webId in con.lookupWebs) {
                    var web;
                    if (webId == currentWebId) {
                        web = con.web;
                    } else {
                        web = site.openWeb(new SP.Guid(webId));
                        if (web == null) continue;
                    }

                    var currentListId = con.urlParams.list.toLowerCase();
                    var lists = con.lookupWebs[webId];
                    for (var listId in lists) {
                        var list;
                        if (listId == currentListId) {
                            list = con.list;
                        } else {
                            list = web.get_lists().getById(new SP.Guid(listId));
                            if (list == null) continue;
                        }

                        var fields = list.get_fields();
                        var showFields = lists[listId];
                        con.lookupLists[listId] = {};
                        var lookupFields = con.lookupLists[listId];
                        for (var i = 0; i < showFields.length; i++) {
                            var showField = showFields[i];
                            lookupFields[showField] = fields.getByInternalNameOrTitle(showField);
                            con.context.load(con.lookupLists[listId][showField]);
                        }
                    }
                }

                con.context.executeQueryAsync(function () {
                    initLookupFieldInfo(con);
                    addFilter(con);
                });
            } else {
                addFilter(con);
            }

            $(".as-row-limit", con.element).val(con.defaultView.get_rowLimit());
        });

        // when the add filter button is clicked
        $("a.as-add-filter", this).click(function () {
            if (con.filterCount < 10) {
                addFilter(con);
                if (con.filterCount >= 10) {
                    $(this).hide();
                }
            }
        });

        // when the ok button is clicked
        $(".as-ok", this).click(function () {
            search(con);
        });

        // when the cancel button is clicked
        $(".as-cancel", this).click(function () {
            location.href = con.list.get_defaultViewUrl();
        });

        // when the reset button is clicked
        $(".as-reset", this).click(function () {
            location.reload();
        });

        return this;
    };

    function getUrlParams() {
        var search = location.search;
        if (search.length > 0 && search.charAt(0) == '?') search = search.substring(1);
        if (search.length == 0) return {};

        var paramArray = search.split("&");
        var params = {};
        for (var i = 0; i < paramArray.length; i++) {
            var nameValue = paramArray[i].split("=");
            if (nameValue.length == 2) {
                params[decodeURIComponent(nameValue[0]).toLowerCase()] = decodeURIComponent(nameValue[1]);
            }
        }
        return params;
    }

    function detectRegion() {
        asRegion.browserTimezoneOffset = asRegion.timezoneOffset - (new Date()).getTimezoneOffset();

        // convert format to jQuery UI datepicker format
        var dateFormat = asRegion.dateFormat;
        if (dateFormat.indexOf("yyy") >= 0) {
            dateFormat = dateFormat.replace("yyyy", "yy").replace("yyy", "yy");
        } else {
            dateFormat = dateFormat.replace("yy", "y");
        }
        if (dateFormat.indexOf("MMM") >= 0) {
            dateFormat = dateFormat.replace("MMMM", "MM").replace("MMM", "M");
        } else {
            dateFormat = dateFormat.replace("MM", "mm").replace("M", "m");
        }
        if (dateFormat.indexOf("ddd") >= 0) {
            dateFormat = dateFormat.replace("dddd", "DD").replace("ddd", "D");
        } else {
        }
        asRegion.dateFormat = dateFormat;

        // number separator
        asRegion.jsDecimalSeparator = ((1.1) + "").substr(1, 1);
        asRegion.replaceDecimalSeparator = (asRegion.jsDecimalSeparator != asRegion.decimalSeparator);
    }

    function initFieldInfo(con) {
        con.fieldInfo = {};
        con.lookupWebs = {};
        con.lookupListCount = 0;
        var fieldEnumerator = con.fields.getEnumerator();
        while (fieldEnumerator.moveNext()) {
            var field = fieldEnumerator.get_current();
            if (field.get_hidden()) continue;
            var fieldType = field.get_fieldTypeKind();
            if (fieldType == SP.FieldType.computed) continue;
            var lookupField, lookupList, showField;
            if (fieldType == SP.FieldType.lookup) {
                lookupField = con.context.castTo(field, SP.FieldLookup);
                lookupList = lookupField.get_lookupList();
                if (!lookupList || lookupList.length == 0) continue;
                showField = lookupField.get_lookupField();
                if (!showField || showField.length == 0) continue;
            }
            var name = field.get_internalName();
            var fieldInfo = { name: name, fieldType: fieldType, queryType: fieldType, resultType: fieldType, title: field.get_title() };
            switch (fieldType) {
                case SP.FieldType.note:
                    setNoteFieldInfo(fieldInfo, field, con);
                    break;
                case SP.FieldType.number:
                    setNumberFieldInfo(fieldInfo, field);
                    break;
                case SP.FieldType.currency:
                    setCurrencyFieldInfo(fieldInfo, field, con);
                    break;
                case SP.FieldType.dateTime:
                    setDateTimeFieldInfo(fieldInfo, field, con);
                    break;
                case SP.FieldType.lookup:
                    var webId = lookupField.get_lookupWebId().toString();
                    var webs = con.lookupWebs;
                    if (!webs[webId]) {
                        webs[webId] = {};
                    }
                    var lists = webs[webId];
                    if (!lists[lookupList]) {
                        lists[lookupList] = new Array();
                        con.lookupListCount++;
                    }
                    lists[lookupList].push(showField);
                    fieldInfo.listId = lookupList;
                    fieldInfo.showField = showField;
                    fieldInfo.multiple = lookupField.get_allowMultipleValues();
                    break;
                case SP.FieldType.user:
                    var userField = con.context.castTo(field, SP.FieldUser);
                    fieldInfo.multiple = userField.get_allowMultipleValues();
                    break;
                case SP.FieldType.URL:
                    var urlField = con.context.castTo(field, SP.FieldUrl);
                    fieldInfo.displayFormat = urlField.get_displayFormat();
                    break;
                case SP.FieldType.calculated:
                    setCalculatedFieldInfo(fieldInfo, field, con); // fieldInfo.queryType is changed
                    fieldInfo.resultType = fieldInfo.queryType;
                    break;
            }
            con.fieldInfo[name] = fieldInfo;
        }
    }

    function initLookupFieldInfo(con) {
        for (var name in con.fieldInfo) {
            var fieldInfo = con.fieldInfo[name];
            if (fieldInfo.fieldType != SP.FieldType.lookup) continue;
            var listId = fieldInfo.listId;
            var showField = fieldInfo.showField;
            if (!con.lookupLists[listId]) continue;
            var lookupFields = con.lookupLists[listId];
            if (!lookupFields[showField]) continue;
            var field = lookupFields[showField];
            fieldInfo.lookupType = field.get_fieldTypeKind();
            switch (fieldInfo.lookupType) {
                case SP.FieldType.number:
                    setNumberFieldInfo(fieldInfo, field);
                    fieldInfo.queryType = fieldInfo.lookupType;
                    break;
                case SP.FieldType.currency:
                    setCurrencyFieldInfo(fieldInfo, field, con);
                    fieldInfo.queryType = fieldInfo.lookupType;
                    break;
                case SP.FieldType.dateTime:
                    setDateTimeFieldInfo(fieldInfo, field, con);
                    fieldInfo.queryType = fieldInfo.lookupType;
                    break;
                case SP.FieldType.calculated:
                    setCalculatedFieldInfo(fieldInfo, field, con); // fieldInfo.queryType is changed
                    break;
            }
        }
    }

    function setNoteFieldInfo(fieldInfo, field, con) {
        var noteField = con.context.castTo(field, SP.FieldMultiLineText);
        fieldInfo.richText = noteField.get_richText();
    }

    function setNumberFieldInfo(fieldInfo, field) {
        var numberXml = field.get_schemaXml();
        fieldInfo.decimals = getDecimalsFromXml(numberXml);
        fieldInfo.percentage = isPercentageFromXml(numberXml);
    }

    function setCurrencyFieldInfo(fieldInfo, field, con) {
        var currencyField = con.context.castTo(field, SP.FieldCurrency);
        fieldInfo.currencyLocaleId = currencyField.get_currencyLocaleId();
        var numberXml = field.get_schemaXml();
        fieldInfo.decimals = getDecimalsFromXml(numberXml);
    }

    function setDateTimeFieldInfo(fieldInfo, field, con, lookup) {
        if (fieldInfo.fieldType == SP.FieldType.lookup) {
            var datetimeXml = field.get_schemaXml();
            var dateFormat = getAttributeFromXml(datetimeXml, "Format");
            fieldInfo.dateFormat = (dateFormat == "DateOnly") ? SP.DateTimeFieldFormatType.dateOnly : SP.DateTimeFieldFormatType.dateTime;
        } else {
            var datetimeField = con.context.castTo(field, SP.FieldDateTime);
            fieldInfo.dateFormat = datetimeField.get_displayFormat();
        }
    }

    function setCalculatedFieldInfo(fieldInfo, field, con) {
        var calcField = con.context.castTo(field, SP.FieldCalculated);
        fieldInfo.queryType = calcField.get_outputType();
        switch (fieldInfo.queryType) {
            case SP.FieldType.dateTime:
                fieldInfo.dateFormat = calcField.get_dateFormat();
                break;
            case SP.FieldType.currency:
            case SP.FieldType.number:
                var numberXml = field.get_schemaXml();
                fieldInfo.decimals = getDecimalsFromXml(numberXml);
                if (fieldInfo.queryType == SP.FieldType.number) {
                    fieldInfo.percentage = isPercentageFromXml(numberXml);
                } else { // SP.FieldType.currency
                    var lcid = getAttributeFromXml(numberXml, "LCID");
                    if (lcid == null) {
                        fieldInfo.currencyLocaleId = _spPageContextInfo.webLanguage;
                    } else {
                        fieldInfo.currencyLocaleId = parseInt(lcid, 10);
                    }
                }
                break;
        }
    }

    function getDecimalsFromXml(xml) {
        var decimals = getAttributeFromXml(xml, "Decimals");
        if (decimals == null) return -1;
        return Math.min(5, parseInt(decimals, 10));
    }

    function getAttributeFromXml(xml, name) {
        var pos = xml.indexOf(name + '="');
        if (pos < 0) return null;
        var valuePos = pos + name.length + 2;
        var endPos = xml.indexOf('"', valuePos);
        if (endPos < 0) return null;
        return xml.substr(valuePos, endPos - valuePos);
    }

    function isPercentageFromXml(xml) {
        return xml.indexOf('Percentage="TRUE"') > 0;
    }

    function addFilter(con) {

        var filterIndex = con.filterCount++;
        var html = '<div class="cb-ui-row" filterIndex="' + filterIndex + '">';

        // label for frist filter
        if (filterIndex == 0) {
            html += '<label class="as-label">' + asResources.Filter + '</label> ';
        }

        // field and operator
        html += '<select filterIndex="' + filterIndex + '" class="as-filter">' +
            '<option value="" queryType="' + SP.FieldType.invalid + '">' + asResources.OptionNone + '</option>';
        html += createFieldOptions(con);
        html += '</select> <select filterIndex="' + filterIndex + '" class="as-operator">';

        // operator options
        for (var operatorKey in operators.general) {
            var operatorText = operators.general[operatorKey];
            html += '<option value="' + operatorKey + '">' + operatorText + '</option>';
        }

        // text input, date time picker
        html += '</select> <input type="text" filterIndex="' + filterIndex + '" class="as-text ms-input" style="width: 200px;" /> ' +
            '<span class="as-date-outer"><input type="text" class="as-date ms-input" /></span><span class="as-datetime"></span></div>';

        var filterRow = $(html).appendTo(con.filtersElement);

        var options = { showOn: "both", buttonImage: "/_layouts/images/calendar.gif", buttonImageOnly: true, dateFormat: asRegion.dateFormat, hoursMode24: asRegion.time24 };

        // for Date only field
        var datepicker = $('.as-date', filterRow).datepicker(options);
        $('.as-date-outer', filterRow).css("display", "none");

        // for Date and Time field
        var datetimepicker = $('.as-datetime', filterRow).datetimepicker(options);
        $('.dtp-date', datetimepicker).addClass("ms-input");
        datetimepicker.css("display", "none");

        $('img', filterRow).attr("align", "absmiddle");

        // when a filter field is changed
        $("select.as-filter", filterRow).change(function () {
            var $filterSelect = $(this);
            var fieldValue = $filterSelect.val();
            var $option = $('option[value="' + fieldValue + '"]', $filterSelect);
            var queryType = parseInt($option.attr("queryType"), 10);
            var index = $filterSelect.attr("filterIndex");
            var operatorType = getOperatorType(queryType);
            changeOperator($('select.as-operator[filterIndex="' + index + '"]', filterRow), operatorType);
            switch (operatorType) {
                case "dateTime":
                    if (parseInt($option.attr("dateFormat"), 10) == SP.DateTimeFieldFormatType.dateOnly) {
                        $(".as-text", filterRow).css("display", "none");
                        $(".as-date-outer", filterRow).css("display", "");
                        $(".as-datetime", filterRow).css("display", "none");
                    } else {
                        $(".as-text", filterRow).css("display", "none");
                        $(".as-date-outer", filterRow).css("display", "none");
                        $(".as-datetime", filterRow).css("display", "");
                    }
                    break;
                case "boolean":
                    $(".as-text", filterRow).css("display", "none");
                    $(".as-date-outer", filterRow).css("display", "none");
                    $(".as-datetime", filterRow).css("display", "none");
                    break;
                default:
                    $(".as-text", filterRow).css("display", "");
                    $(".as-date-outer", filterRow).css("display", "none");
                    $(".as-datetime", filterRow).css("display", "none");
                    break;
            }
        });
    }

    function createFieldOptions(con) {
        var html = "";
        for (var fieldName in con.fieldInfo) {
            var field = con.fieldInfo[fieldName];
            if (field.queryType == SP.FieldType.dateTime) {
                html += '<option value="' + field.name + '" queryType="' + field.queryType + '" dateFormat="' + field.dateFormat + '">' + htmlEscape(field.title) + '</option>';
            } else {
                html += '<option value="' + field.name + '" queryType="' + field.queryType + '">' + htmlEscape(field.title) + '</option>';
            }
        }
        return html;
    }

    function changeOperator($select, operatorType) {
        $select.empty();
        var operator = operators[operatorType];
        for (var operatorKey in operator) {
            $select.append('<option value="' + operatorKey + '">' + operator[operatorKey] + '</option>');
        }
    }

    function search(con) {
        var resultArea = $(".as-result", con.element).empty().append('<label class="as-label">' + asResources.SearchResult + '</label>');

        var andOr = $('select.as-andor', con.element).val();

        con.viewFields = ["Title"];
        var viewFieldsEnumerator = con.defaultViewFields.getEnumerator();
        while (viewFieldsEnumerator.moveNext()) {
            var viewField = viewFieldsEnumerator.get_current();
            if (con.fieldInfo[viewField] && $.inArray(viewField, con.viewFields) == -1) {
                con.viewFields.push(viewField);
            }
        }

        var queryFields = [];

        var filterField;
        for (var i = 0; i < con.filterCount; i++) {
            // filter row
            var filterRow = $('div.cb-ui-row[filterIndex="' + i + '"]', con.element);

            // filter field
            filterField = $('select.as-filter', filterRow);

            // field name
            var fieldName = filterField.val();
            if (!fieldName) continue;
            if ($.inArray(fieldName, con.viewFields) == -1) {
                con.viewFields.push(fieldName);
            }
            var field = con.fieldInfo[fieldName];

            // search operator
            var queryField = {
                name: fieldName,
                queryType: field.queryType,
                resultType: field.resultType,
                operator: $('select.as-operator', filterRow).val()
            };

            // other parameters
            switch (queryField.queryType) {
                case SP.FieldType.dateTime:
                    queryField.dateFormat = field.dateFormat;
                    break;
                case SP.FieldType.number:
                    queryField.percentage = field.percentage;
                    break;
            }

            // search value
            switch (queryField.queryType) {
                case SP.FieldType.dateTime:
                    if (queryField.dateFormat == SP.DateTimeFieldFormatType.dateOnly) {
                        queryField.date = $('input.as-date', filterRow).datepicker("getDate");
                    } else {
                        queryField.date = $('span.as-datetime', filterRow).datetimepicker("getDate");
                    }
                    break;
                case SP.FieldType.boolean:
                    // do nothing
                    break;
                default:
                    queryField.text = $('input.as-text', filterRow).val();
                    if (!queryField.text) queryField.text = "";
            }

            queryFields.push(queryField);
        }

        // row limit
        con.rowLimit = parseInt($(".as-row-limit", con.element).val(), 10);

        // grid
        resultArea.append('<table class="as-grid" cellspacing="0"></table>');
        initHeader(con);
        initPager(con);

        var viewXml = {};

        // view fields query
        viewXml.viewFields = '<ViewFields>';
        for (var i = 0; i < con.viewFields.length; i++) {
            viewXml.viewFields += '<FieldRef Name="' + con.viewFields[i] + '" />';
        }
        viewXml.viewFields += '</ViewFields>';

        if (queryFields.length) {
            viewXml.where = '<Where>';
            switch (queryFields.length) {
                case 1:
                    viewXml.where += createFilterCAML(queryFields[0]);
                    break;
                case 2:
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[0]);
                    viewXml.where += createFilterCAML(queryFields[1]);
                    viewXml.where += createEndAndOr(andOr);
                    break;
                case 3:
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[0]);
                    viewXml.where += createFilterCAML(queryFields[1]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[2]);
                    viewXml.where += createEndAndOr(andOr);
                    break;
                case 4:
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[0]);
                    viewXml.where += createFilterCAML(queryFields[1]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[2]);
                    viewXml.where += createFilterCAML(queryFields[3]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    break;
                case 5:
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[0]);
                    viewXml.where += createFilterCAML(queryFields[1]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[2]);
                    viewXml.where += createFilterCAML(queryFields[3]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[4]);
                    viewXml.where += createEndAndOr(andOr);
                    break;
                case 6:
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[0]);
                    viewXml.where += createFilterCAML(queryFields[1]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[2]);
                    viewXml.where += createFilterCAML(queryFields[3]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[4]);
                    viewXml.where += createFilterCAML(queryFields[5]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    break;
                case 7:
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[0]);
                    viewXml.where += createFilterCAML(queryFields[1]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[2]);
                    viewXml.where += createFilterCAML(queryFields[3]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[4]);
                    viewXml.where += createFilterCAML(queryFields[5]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[6]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    break;
                case 8:
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[0]);
                    viewXml.where += createFilterCAML(queryFields[1]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[2]);
                    viewXml.where += createFilterCAML(queryFields[3]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[4]);
                    viewXml.where += createFilterCAML(queryFields[5]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[6]);
                    viewXml.where += createFilterCAML(queryFields[7]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    break;
                case 9:
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[0]);
                    viewXml.where += createFilterCAML(queryFields[1]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[2]);
                    viewXml.where += createFilterCAML(queryFields[3]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[4]);
                    viewXml.where += createFilterCAML(queryFields[5]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[6]);
                    viewXml.where += createFilterCAML(queryFields[7]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[8]);
                    viewXml.where += createEndAndOr(andOr);
                    break;
                case 10:
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[0]);
                    viewXml.where += createFilterCAML(queryFields[1]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[2]);
                    viewXml.where += createFilterCAML(queryFields[3]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[4]);
                    viewXml.where += createFilterCAML(queryFields[5]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[6]);
                    viewXml.where += createFilterCAML(queryFields[7]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createBeginAndOr(andOr);
                    viewXml.where += createFilterCAML(queryFields[8]);
                    viewXml.where += createFilterCAML(queryFields[9]);
                    viewXml.where += createEndAndOr(andOr);
                    viewXml.where += createEndAndOr(andOr);
                    break;
            }
            viewXml.where += '</Where>';
        } else {
            viewXml.where = "";
        }

        // row limit query
        viewXml.rowLimit = '<RowLimit>' + con.rowLimit + '</RowLimit>';

        con.viewXml = viewXml;
        con.caml = '<View>' + viewXml.viewFields;
        if (viewXml.where) {
            con.caml += '<Query>' + viewXml.where + '</Query>';
        }
        con.caml += viewXml.rowLimit + '</View>';

        query(con, "first");
    }

    function query(con, posType) {
        var grid = $('table.as-grid', con.element);

        // clear data rows
        grid.find('tr.as-row-data').remove();

        var caml = new SP.CamlQuery();
        caml.set_viewXml(con.caml);
        if (posType == "next" && con.nextPos != null) {
            caml.set_listItemCollectionPosition(con.nextPos);
        } else if (posType == "prev" && con.prevPos.length > 0) {
            caml.set_listItemCollectionPosition(con.prevPos[con.prevPos.length - 1]);
        } else {
            posType = "first";
        }

        var webUrl = con.web.get_serverRelativeUrl();
        if (webUrl == "/") webUrl = "";

        var dispUrl = con.list.get_defaultDisplayFormUrl();

        var listItems = con.list.getItems(caml);
        con.context.load(listItems);
        con.context.executeQueryAsync(function () {
            var lastRow = $("tr:last", grid);
            var listItemsEnumerator = listItems.getEnumerator();
            while (listItemsEnumerator.moveNext()) {
                var listItem = listItemsEnumerator.get_current();
                var row = $('<tr class="as-row-data"></tr>').insertBefore(lastRow); // .appendTo(grid);
                // link to item
                var id = listItem.get_id() + "";
                var itemUrl = dispUrl + '?ID=' + id;
                row.append('<td class="ui-widget-content"><a href="' + itemUrl + '" target="_blank"><img src="/_layouts/images/icgen.gif" style="border: 0;" /></a></td>');
                // view fields
                for (var j = 0; j < con.viewFields.length; j++) {
                    var value;
                    var viewField = con.viewFields[j];
                    var field = con.fieldInfo[viewField];

                    // field value
                    if (viewField == "ID") {
                        value = listItem.get_id();
                    } else {
                        value = listItem.get_item(viewField);
                    }

                    if (value == null) {
                        row.append('<td class="ui-widget-content"></td>');
                        continue;
                    }

                    if (field.resultType == SP.FieldType.lookup || field.resultType == SP.FieldType.user) {
                        var lookupNull = false;
                        if ($.isArray(value)) {
                            lookupNull = (value.length == 0);
                        } else if (field.multiple) {
                            lookupNull = true;
                        } else {
                            lookupNull = (value.get_lookupValue() == null);
                        }
                        if (lookupNull) {
                            row.append('<td class="ui-widget-content"></td>');
                            continue;
                        }
                    }

                    var nowrap = true;

                    switch (field.queryType) {
                        case SP.FieldType.integer:
                            value = '<div class="as-right">' + formatInteger(value) + '</div>';
                            break;

                        case SP.FieldType.number:
                        case SP.FieldType.currency:
                            if (field.resultType == SP.FieldType.lookup) {
                                if ($.isArray(value)) {
                                    var formattedNumbers = new Array();
                                    for (var lookupIndex = 0; lookupIndex < value.length; lookupIndex++) {
                                        var val = value[lookupIndex]
                                        var number = parseFloat(val.get_lookupValue());
                                        if (field.queryType == SP.FieldType.number) {
                                            formattedNumbers.push(formatNumberField(number, field));
                                        } else {
                                            formattedNumbers.push(formatCurrencyField(number, field));
                                        }
                                    }
                                    value = formattedNumbers.join("; ");
                                    break;
                                } else {
                                    value = parseFloat(value.get_lookupValue());
                                }
                            }
                            if (field.queryType == SP.FieldType.number) {
                                value = '<div class="as-right">' + formatNumberField(value, field) + '</div>';
                            } else {
                                value = '<div class="as-right">' + formatCurrencyField(value, field) + '</div>';
                            }
                            break;

                        case SP.FieldType.dateTime:
                            if (field.resultType == SP.FieldType.lookup) {
                                if ($.isArray(value)) {
                                    var formattedDateTimes = new Array();
                                    for (var lookupIndex = 0; lookupIndex < value.length; lookupIndex++) {
                                        var val = value[lookupIndex]
                                        var date = parseISO8601(val.get_lookupValue());
                                        formattedDateTimes.push(formatDateTimeField(date, field));
                                    }
                                    value = formattedDateTimes.join("; ");
                                    break;
                                } else {
                                    value = parseISO8601(value.get_lookupValue());
                                }
                            } else {
                                value = new Date(value.toString());
                            }
                            value = formatDateTimeField(value, field);
                            break;

                        case SP.FieldType.attachments:
                            value = value ? '<div class="as-center"><img src="/_layouts/images/attach.gif" /></div>' : "";
                            break;

                        case SP.FieldType.boolean:
                            value = htmlEscape(value ? coreResources.Yes : coreResources.No);
                            break;

                        case SP.FieldType.user:
                            if ($.isArray(value)) {
                                var formattedUsers = new Array();
                                for (var userIndex = 0; userIndex < value.length; userIndex++) {
                                    var val = value[userIndex];
                                    formattedUsers.push(formatUserField(val, webUrl));
                                }
                                value = formattedUsers.join("; ");
                            } else {
                                value = formatUserField(value, webUrl);
                            }
                            break;

                        case SP.FieldType.note:
                            if (field.richText) {
                                value = value + "";
                            } else {
                                value = htmlEscape(value + "");
                            }
                            nowrap = false;
                            break;

                        case SP.FieldType.URL:
                            if (field.displayFormat == SP.UrlFieldFormatType.image) {
                                value = '<img src="' + value.get_url() + '" alt="' + htmlEscape(value.get_description()) + '" />';
                            } else {
                                var desc = value.get_description();
                                if (!desc.length) {
                                    desc = value.get_url();
                                }
                                value = '<a href="' + value.get_url() + '" target="_blank">' + htmlEscape(desc) + '</a>';
                            }
                            nowrap = false;
                            break;

                        case SP.FieldType.lookup:
                            if ($.isArray(value)) {
                                var values = new Array();
                                for (var lookupIndex = 0; lookupIndex < value.length; lookupIndex++) {
                                    var val = value[lookupIndex];
                                    values.push(htmlEscape(val.get_lookupValue()));
                                }
                                value = values.join("; ");
                            } else {
                                value = htmlEscape(value.get_lookupValue());
                            }
                            break;

                        case SP.FieldType.text:
                            if (viewField == "Title") {
                                value = '<a href="' + itemUrl + '" target="_blank">' + htmlEscape(value + "") + '</a>';
                                nowrap = false;
                                break;
                            }
                        default:
                            value = htmlEscape(value + "");
                            nowrap = false;
                    }

                    if (nowrap) {
                        row.append('<td class="ui-widget-content" nowrap="nowrap">' + value + '</td>');
                    } else {
                        row.append('<td class="ui-widget-content">' + value + '</td>');
                    }
                }
            }

            if (posType == "next") {
                con.prevPos.push(con.curPos);
                con.curPos = con.nextPos;
            } else if (posType == "prev") {
                con.curPos = con.prevPos.pop();
            } else { // first
                con.curPos = null;
                con.prevPos = new Array();
            }

            con.nextPos = listItems.get_listItemCollectionPosition();

            if (con.prevPos.length > 0) {
                $("img.as-pager-first", grid).css("cursor", "pointer").attr("src", "/_layouts/images/arrowendleft_dark.gif");
                $("img.as-pager-prev", grid).css("cursor", "pointer").attr("src", "/_layouts/images/arrowleft_light.gif");
            } else {
                $("img.as-pager-first", grid).css("cursor", "default").attr("src", "/_layouts/images/arrowendleft_light.gif");
                $("img.as-pager-prev", grid).css("cursor", "default").attr("src", "/_layouts/images/arrowleft_dark.gif");
            }
            if (con.nextPos != null) {
                $("img.as-pager-next", grid).css("cursor", "pointer").attr("src", "/_layouts/images/arrowright_light.gif");
            } else {
                $("img.as-pager-next", grid).css("cursor", "default").attr("src", "/_layouts/images/arrowright_dark.gif");
            }

            $(".as-result").append('<div id="as-search-done"></div>'); // search done flag
        });
    }

    function sort(con, orderBy) {
        if (con.orderBy == orderBy) {
            con.ascending = (!con.ascending);
        } else {
            con.orderBy = orderBy;
            con.ascending = true;
        }
        con.viewXml.orderBy = '<OrderBy><FieldRef Name="' + orderBy + '" Ascending="' + (con.ascending ? 'TRUE' : 'FALSE') + '" /></OrderBy>';
        con.caml = '<View>' + con.viewXml.viewFields + '<Query>' + con.viewXml.where + con.viewXml.orderBy + '</Query>' + con.viewXml.rowLimit + '</View>';

        query(con, "first");
    }

    function initHeader(con) {
        var grid = $("table.as-grid", con.element);
        var headers = $('<tr class="as-row-header"></tr>').appendTo(grid);
        headers.append('<th class="ui-state-default as-cell-header">&nbsp;</th>');
        for (var i = 0; i < con.viewFields.length; i++) {
            var fieldName = con.viewFields[i];
            headers.append('<th class="ui-state-default as-cell-header" fieldName="' + fieldName + '" nowrap="nowrap">' + htmlEscape(con.fieldInfo[fieldName].title) + '<img align="absmiddle" style="display: none;" /></th>');
        }

        $("th.as-cell-header", grid).css("cursor", "pointer").hover(function () {
            $(this).addClass("ui-state-hover");
        }, function () {
            $(this).removeClass("ui-state-hover");
        }).click(function () {
            $('img', headers).hide();
            var orderBy = $(this).attr("fieldName");
            if (con.orderBy == orderBy && con.ascending) {
                $('img', this).attr("src", "/_layouts/images/arrdowna.gif").show();
            } else {
                $('img', this).attr("src", "/_layouts/images/arrupa.gif").show();
            }
            sort(con, orderBy);
        });
    }

    function initPager(con) {
        var grid = $("table.as-grid", con.element);
        var rowHtml = '<tr class="as-row-pager"></tr>';
        grid.prepend(rowHtml);
        grid.append(rowHtml);

        var rows = $("tr.as-row-pager");
        rows.append('<th class="as-cell-pager" colspan="' + con.viewFields.length + '"></th>');

        var pagers = $("th.as-cell-pager");
        pagers.append('<img src="/_layouts/images/arrowendleft_light.gif" class="as-pager-first" />');
        pagers.append('<img src="/_layouts/images/arrowleft_dark.gif" class="as-pager-prev" />');
        pagers.append('<img src="/_layouts/images/arrowright_dark.gif" class="as-pager-next" />');

        var rowLimitLabel = con.rowLimit + "";
        pagerFirstLabel = asResources.FirstItems.replace("{0}", rowLimitLabel);
        pagerPrevLabel = asResources.PrevItems.replace("{0}", rowLimitLabel);
        pagerNextLabel = asResources.NextItems.replace("{0}", rowLimitLabel);
        var pagerFirst = $("img.as-pager-first").attr("title", pagerFirstLabel).attr("alt", "First");
        var pagerPrev = $("img.as-pager-prev").attr("title", pagerPrevLabel).attr("alt", "Previous");
        var pagerNext = $("img.as-pager-next").attr("title", pagerNextLabel).attr("alt", "Next");

        pagerFirst.click(function () {
            if (con.prevPos.length > 0) query(con, "first");
        });
        pagerPrev.click(function () {
            if (con.prevPos.length > 0) query(con, "prev");
        });
        pagerNext.click(function () {
            if (con.nextPos != null) query(con, "next");
        });
    }

    function createBeginAndOr(andOr) {
        return '<' + andOr + '>';
    }

    function createEndAndOr(andOr) {
        return '</' + andOr + '>';
    }

    function createFilterCAML(queryField) {
        var operator = queryField.operator;

        // True or False
        if (operator == "True") {
            return '<Eq><FieldRef Name="' + queryField.name + '" /><Value Type="Boolean">1</Value></Eq>';
        } else if (operator == "False") {
            return '<Neq><FieldRef Name="' + queryField.name + '" /><Value Type="Boolean">1</Value></Neq>';
        }

        // IsNull or IsNotNull
        var queryType = queryField.queryType;
        if (queryType == SP.FieldType.dateTime) {
            if (!queryField.date) {
                if (queryField.operator == "Eq") {
                    return '<IsNull><FieldRef Name="' + queryField.name + '" /></IsNull>';
                } else if (queryField.operator == "Neq") {
                    return '<IsNotNull><FieldRef Name="' + queryField.name + '" /></IsNotNull>';
                }
            }
        } else if (queryField.text.length == 0) {
            if (queryField.operator == "Eq") {
                return '<IsNull><FieldRef Name="' + queryField.name + '" /></IsNull>';
            } else if (queryField.operator == "Neq") {
                return '<IsNotNull><FieldRef Name="' + queryField.name + '" /></IsNotNull>';
            }
            if (queryType == SP.FieldType.integer || queryType == SP.FieldType.number || queryType == SP.FieldType.currency) {
                queryField.text = "0";
            }
        }

        var caml = '<' + queryField.operator + '><FieldRef Name="' + queryField.name + '" />';
        switch (queryType) {
            case SP.FieldType.counter:
            case SP.FieldType.integer:
                var intValue = parseInt(queryField.text, 10);
                if (intValue == NaN) intValue = 0;
                caml += '<Value Type="Integer">' + intValue;
                break;
            case SP.FieldType.number:
                if (queryField.resultType == SP.FieldType.lookup) {
                    caml += '<Value Type="Lookup">';
                } else {
                    caml += '<Value Type="Number">';
                }
                if (queryField.percentage) {
                    caml += percentageStringToNumberString(queryField.text);
                } else {
                    caml += xmlEscape(queryField.text);
                }
                break;
            case SP.FieldType.currency:
                caml += '<Value Type="Currency">' + xmlEscape(queryField.text);
                break;
            case SP.FieldType.dateTime:
                var d = queryField.date;
                if (!d) {
                    caml += '<Value Type="DateTime">';
                } else if (queryField.dateFormat == SP.DateTimeFieldFormatType.dateOnly) {
                    caml += '<Value Type="DateTime">' + d.getFullYear() + '-' + nn(d.getMonth() + 1) + '-' + nn(d.getDate());
                } else {
                    // CAML use the timezone of user profile, not use the timezone of the browser, so comment out the following codes.
                    //if (asRegion.browserTimezoneOffset) {
                    //    d.setTime(d.getTime() + asRegion.browserTimezoneOffset * 60 * 1000);
                    //}
                    caml += '<Value Type="DateTime" IncludeTimeValue="TRUE">' +
                            d.getFullYear() + '-' + nn(d.getMonth() + 1) + '-' + nn(d.getDate()) + 'T' +
                            nn(d.getHours()) + ':' + nn(d.getMinutes()) + ':' + nn(d.getSeconds()) + 'Z';
                    //    d.getUTCFullYear() + '-' + nn(d.getUTCMonth() + 1) + '-' + nn(d.getUTCDate()) + 'T' +
                    //    nn(d.getUTCHours()) + ':' + nn(d.getUTCMinutes()) + ':' + nn(d.getUTCSeconds()) + 'Z';
                }
                break;
            default:
                caml += '<Value Type="Text">' + xmlEscape(queryField.text);
                break;
        }
        caml += '</Value></' + queryField.operator + '>';
        return caml;
    }

    function createNullFilterCAML(queryField) {
        if (queryField.operator == "Eq") {
            return '<IsNull><FieldRef Name="' + queryField.name + '" /></IsNull>';
        } else if (queryField.operator == "Neq") {
            return '<IsNotNull><FieldRef Name="' + queryField.name + '" /></IsNotNull>';
        }
        return null;
    }

    function htmlEscape(text) {
        return text ? (text.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#039;").replace(/</g, "&lt;").replace(/>/g, "&gt;")) : "";
    }

    function xmlEscape(text) {
        return text ? (text.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&apos;").replace(/</g, "&lt;").replace(/>/g, "&gt;")) : "";
    }

    function getOperatorType(queryType) {
        switch (queryType) {
            case SP.FieldType.counter:
            case SP.FieldType.currency:
            case SP.FieldType.integer:
            case SP.FieldType.number:
                return "number";

            case SP.FieldType.dateTime:
                return "dateTime";

            case SP.FieldType.attachments:
            case SP.FieldType.boolean:
                return "boolean";

            case SP.FieldType.user:
                return "user";

            case SP.FieldType.invalid:
                return "general";

            default:
                return "text";
        }
    }

    function nn(num) {
        return ((num < 10) ? "0" : "") + num;
    }

    function formatInteger(integerNumber) {
        return formatIntegerString(integerNumber.toString());
    }

    function formatIntegerString(integerString) {
        if (integerString.length > 3) {
            return integerString.replace(/([0-9]+?)(?=(?:[0-9]{3})+$)/g, '$1' + asRegion.thousandSeparator);
        } else {
            return integerString;
        }
    }

    function formatNumberField(number, field) {
        if (field.percentage) {
            if (field.decimals < 0) {
                if (number == 0) {
                    return "0 %";
                } else {
                    return formatPercentageAutomatic(number) + " %";
                }
            }
            number *= 100;
        }

        if (field.decimals == 0) {
            return formatIntegerString(number.toFixed(0)) + (field.percentage ? " %" : "");
        } else if (field.decimals > 0) {
            numberString = number.toFixed(field.decimals);
            if (asRegion.replaceDecimalSeparator) {
                numberString = numberString.replace(asRegion.jsDecimalSeparator, asRegion.decimalSeparator);
            }
            return formatNumberString(numberString) + (field.percentage ? " %" : "");
        } else {
            numberString = number.toString();
            if (asRegion.replaceDecimalSeparator && numberString.indexOf(asRegion.jsDecimalSeparator) >= 0) {
                numberString = numberString.replace(asRegion.jsDecimalSeparator, asRegion.decimalSeparator);
            }
            return formatNumberString(numberString) + (field.percentage ? " %" : "");
        }
    }

    function formatNumberString(numberString) {
        var pos = numberString.indexOf(asRegion.decimalSeparator);
        if (pos >= 0) {
            return formatIntegerString(numberString.substr(0, pos)) + numberString.substr(pos);
        } else {
            return formatIntegerString(numberString);
        }
    }

    function formatPercentageAutomatic(number) {
        var numberString = number.toString();
        var pos = numberString.indexOf(asRegion.jsDecimalSeparator);
        if (pos < 0) {
            return formatIntegerString(numberString + "00");
        }

        var decimals = Math.max(0, numberString.length - (pos + 1) - 2);
        var percentageString = (number * 100).toFixed(decimals);
        if (asRegion.replaceDecimalSeparator && decimals > 0) {
            percentageString = percentageString.replace(asRegion.jsDecimalSeparator, asRegion.decimalSeparator);
        }
        return formatNumberString(percentageString);
    }

    function percentageStringToNumberString(percentageString) {
        var numberString;
        var percentage = parseFloat(percentageString)
        percentageString = percentage.toString();
        var pos = percentageString.indexOf(asRegion.jsDecimalSeparator);
        if (pos < 0) {
            return (percentage / 100).toString();
        } else {
            var decimals = percentageString.length - (pos + 1) + 2;
            return (percentage / 100).toFixed(decimals);
        }
    }

    function formatCurrencyField(number, field) {
        var decimals = (field.decimals < 0) ? 2 : field.decimals;
        var currencyInfo = null;
        if (field.currencyLocaleId && asCurrency[field.currencyLocaleId]) {
            currencyInfo = asCurrency[field.currencyLocaleId];
        }

        var val;
        if (decimals == 0) {
            val = formatIntegerString(number.toFixed(0));
        } else {
            var numberString = number.toFixed(decimals);
            if (asRegion.replaceDecimalSeparator) {
                numberString = numberString.replace(asRegion.jsDecimalSeparator, asRegion.decimalSeparator);
            }
            val = formatNumberString(numberString);
        }

        if (currencyInfo) {
            val = val.replace("-", "");
            var symbol = currencyInfo.symbol;
            if (number < 0) {
                // negative pattern
                switch (currencyInfo.negativePattern) {
                    case 0: val = "(" + symbol + val + ")"; break;
                    case 1: val = "-" + symbol + val; break;
                    case 2: val = symbol + "-" + val; break;
                    case 3: val = symbol + val + "-"; break;
                    case 4: val = "(" + val + symbol + ")"; break;
                    case 5: val = "-" + val + symbol; break;
                    case 6: val = val + "-" + symbol; break;
                    case 7: val = val + symbol + "-"; break;
                    case 8: val = "-" + val + " " + symbol; break;
                    case 9: val = "-" + symbol + " " + val; break;
                    case 10: val = val + " " + symbol + "-"; break;
                    case 11: val = symbol + " " + val + "-"; break;
                    case 12: val = symbol + " -" + val; break;
                    case 13: val = val + "- " + symbol; break;
                    case 14: val = "(" + symbol + " " + val + ")"; break;
                    case 15: val = "(" + val + " " + symbol + ")"; break;
                }
            } else {
                // positive pattern
                switch (currencyInfo.positivePattern) {
                    case 0: val = symbol + val; break;
                    case 1: val = val + symbol; break;
                    case 2: val = symbol + " " + val; break;
                    case 3: val = val + " " + symbol; break;
                }
            }
        }

        return val;
    }

    function parseISO8601(iso8601) {
        if (iso8601.charAt(iso8601.length - 1) == "Z") {
            iso8601 = iso8601.substr(0, iso8601.length - 1);
        }
        var values = iso8601.split("T");
        var dateValues = values[0].split("-");
        var timeValues = values[1].split(":");
        date = new Date();
        date.setTime(Date.UTC(parseInt(dateValues[0], 10), parseInt(dateValues[1], 10) - 1, parseInt(dateValues[2], 10),
            parseInt(timeValues[0], 10), parseInt(timeValues[1], 10), parseInt(timeValues[2], 10)));
        return date;
    }

    function formatDateTimeField(date, field) {
        if (asRegion.browserTimezoneOffset) {
            date.setTime(date.getTime() - asRegion.browserTimezoneOffset * 60 * 1000);
        }
        var value = $.datepicker.formatDate(asRegion.dateFormat, date);
        if (field.dateFormat == SP.DateTimeFieldFormatType.dateTime) {
            if (asRegion.time24) {
                value += " " + date.getHours() + ":" + nn(date.getMinutes());
            } else {
                var hours = date.getHours() % 12;
                hours = (hours == 0) ? 12 : hours;
                value += " " + hours + ":" + nn(date.getMinutes()) + " " + ((date.getHours() < 12) ? "AM" : "PM");
            }
        }
        return value;
    }

    function formatUserField(userValue, webUrl) {
        var uid = userValue.get_lookupId();
        var userName = userValue.get_lookupValue();
        if (uid) {
            return '<a href="' + webUrl + '/_layouts/userdisp.aspx?ID=' + uid + '" target="_blank">' + htmlEscape(userName + "") + '</a>';
        } else {
            return htmlEscape(userName + "");
        }
    }
})(jQuery);
